﻿using AxZWANPHONELib;
using LitJson;
using RestAPI;
using System;
using System.Linq;
using System.Threading.Tasks;
using TopVisionLog;
//using TopVisionVideoStream.RestAPI;
//using System.Diagnostics;

namespace TopVisionVideoStream
{
    public delegate void VideoCallResultHandler(CallStatusType e);

    public delegate void VideoCallStatusResultHandler(CallStatusType e);

    public delegate void VideoConfCallResultHandler(ConfCallResponse result);

    public delegate void VideoCallCancelResultHandler(string message);

    public delegate void VideoCallMeHandler(string callingID);

    public delegate void TakephotoCompleteHandler(string _imgUrl);

    public delegate void RemoteScreenTypeHandler(ScreenType screenType);

    public delegate void MessageInfoHandler(string msg);

    //public delegate void TrafficNotifyHandler(int audioSend, int audioRecv, int videoSend, int videoRecv);
    public delegate void TrafficNotifyHandler(int audioSend, int audioRecv, int videoSend, int videoRecv);

    static class Model_VideoConferenc
    {

        #region 视频通话

        public static event VideoCallResultHandler CallResultEvent;

        public static event VideoCallCancelResultHandler CallCancelResultEvent;

        public static event VideoCallMeHandler VideoCallMeEvent;

        public static event RemoteScreenTypeHandler RemoteScreenTypeEvent;

        public static event TrafficNotifyHandler TrafficNotifyEvent;

        public static CallStatusType curCallNumberStatus = CallStatusType.None;

        public static ConferencStatusType ConferencStatus = ConferencStatusType.Ready;

        public static TakephotoCompleteHandler TakephotoCompleteEvent;

        public static MessageInfoHandler MessageInfoEvent;

        private static string callingID;

        public static async void VidelCallAsync(string callID, CallType callType)
        {
            TVLog.WriteLine("MSG:Calling...");

            var tmpStatus = CallStatusType.Calling;

            if (callID == Configuration.Account)
            {
                tmpStatus = CallStatusType.Failed;

                TVLog.WriteLine("MSG:Call ID is current user");
            }
            else
            {
                var core = Configuration.Core;

                bool ret = false;

                if (Configuration.CompanyID == "")
                {
                    Configuration.UpdateCompanyInformationFormServer();

                    await Task.Delay(1000);
                }

                tmpStatus = await Configuration.GetAccountStatusAsync(callID);

                if (tmpStatus == CallStatusType.Online)
                {

                    ret = core.bCreateMultiCall("1.0", callID, 2) != 0;

                    if (!ret)
                    {
                        VideoCallCancel();

                        tmpStatus = CallStatusType.Failed;

                        TVLog.WriteLine("WAR:operation failed");
                    }
                }
                else
                {
                    TVLog.WriteLine("MSG:id(" + callID + ") you call is failed :" + tmpStatus.ToString());
                }
            }

            UpdateStatus(tmpStatus);
        }

        public static void RegistCallEvent()
        {
            var core = Configuration.Core;

            core.PhoneConnected += Core_PhoneConnected;

            core.ReportMemberStatus += Core_ReportMemberStatus;

            core.MessageInfo += Core_MessageInfo;

            core.TrafficNotify += Core_TrafficNotify;
        }

        private static void Core_TrafficNotify(object sender, _DZwanPhoneEvents_TrafficNotifyEvent e)
        {
            TrafficNotifyEvent?.Invoke(e.audioSend, e.audioRecv, e.videoSend, e.videoRecv);
        }

        public static void UnRegistCallEvent()
        {
            var core = Configuration.Core;

            core.PhoneConnected -= Core_PhoneConnected;

            core.ReportMemberStatus -= Core_ReportMemberStatus;

            core.MessageInfo -= Core_MessageInfo;

            core.TrafficNotify -= Core_TrafficNotify;

        }

        private static void Core_MessageInfo(object sender, _DZwanPhoneEvents_MessageInfoEvent e)
        {
            var _msg = e.strInfo;

            if (_msg.StartsWith("图片地址,"))
            {
                if (TakephotoCompleteEvent != null)
                {
                    string _imgUrl = _msg.Replace("图片地址,", "");

                    TakephotoCompleteEvent.Invoke(_imgUrl);
                }
            }

            MessageInfoEvent?.Invoke(_msg);
        }

        private static void Core_ReportMemberStatus(object sender, _DZwanPhoneEvents_ReportMemberStatusEvent e)
        {
            var tempStatus = (CallStatusType)e.lStatus;

            Console.WriteLine("e.Status : " + e.lStatus + "  > " + tempStatus.ToString());

            Console.WriteLine("Time :" + DateTime.Now);

            UpdateStatus(tempStatus);
        }

        private static void Core_PhoneConnected(object sender, _DZwanPhoneEvents_PhoneConnectedEvent e)
        {
            var tempStatus = CallStatusType.Connected;

            Console.WriteLine("is connected : " + tempStatus);

            Console.WriteLine("Time :" + DateTime.Now);

            UpdateStatus(tempStatus);
        }

        public static bool VideoCallCancel()
        {
            var core = Configuration.Core;

            var ret = core.bLeaveCall() != 0;

            if (CallCancelResultEvent != null)
            {
                CallCancelResultEvent.Invoke(ret.ToString());
            }

            return ret;
        }

        private static void UpdateStatus(CallStatusType status)
        {
            if (Configuration.CallStatus != status)
            {
                if (status == CallStatusType.Calling)
                {
                    ConferencStatus = ConferencStatusType.Calling;
                }
                else if (status == CallStatusType.Connected)
                {
                    ConferencStatus = ConferencStatusType.Conferencing;

                    TVVS.QosInformation.StartQos();
                }
                else if (status == CallStatusType.CallIn)
                {
                    ConferencStatus = ConferencStatusType.Calling;
                }
                else if (status == CallStatusType.DisConnect)
                {
                    ConferencStatus = ConferencStatusType.Ready;
                    TVVS.QosInformation.StopQos();
                    isMutilCalling = false;
                    Configuration.UpdateVideoConfMembersCancel();

                    //if (isMutilCalling)
                    //{
                    //    VideoConfCtrlHalt();
                    //}
                }
                else
                {
                    //ConferencStatus = ConferencStatusType.Ready;
                    //TVVS.QosInformation.StopQos();

                    //if (isMutilCalling)
                    //{
                    //    VideoConfCtrlHalt();
                    //}
                }

                Configuration.CallStatus = status;

                if (CallResultEvent != null)
                {
                    CallResultEvent.Invoke(status);
                }
            }
        }

        public static void RegistEvent()
        {
            Configuration.Core.SomeOneCallMe += Core_SomeOneCallMe;

            Configuration.Core.ScreenType += Core_ScreenType;
        }

        public static void UnRegistEvent()
        {
            Configuration.Core.SomeOneCallMe -= Core_SomeOneCallMe;
            Configuration.Core.NetworkBrokenNotify -= Core_NetworkBrokenNotify;
            Configuration.Core.ScreenType -= Core_ScreenType;
        }

        private static void Core_NetworkBrokenNotify(object sender, System.EventArgs e)
        {
            VideoCallCancel();
        }

        private static void Core_SomeOneCallMe(object sender, _DZwanPhoneEvents_SomeOneCallMeEvent e)
        {
            if (ConferencStatus == ConferencStatusType.Conferencing | ConferencStatus == ConferencStatusType.Calling)
            {
                return;
            }

            UpdateStatus(CallStatusType.CallIn);

            callingID = e.lpCaller.Split(':')[1].Split('@')[0];

            Configuration.CallingID = callingID;

#if DEBUG
            Console.WriteLine("Calling : " + callingID);
#endif

            if (VideoCallMeEvent != null)
            {
                VideoCallMeEvent.Invoke(callingID);
            }
        }

        public static bool AcceptCall()
        {
            Configuration.CallingID = callingID;

            callingID = "";

            bool ret = Configuration.Core.bAcceptCall(Configuration.CallingID) != 0;

            return ret;
        }

        private static void Core_ScreenType(object sender, _DZwanPhoneEvents_ScreenTypeEvent e)
        {
            if (RemoteScreenTypeEvent != null)
            {
                var _screenType = ScreenType.glass;

                try
                {
                    _screenType = (ScreenType)Enum.Parse(typeof(ScreenType), e.type.ToLower());
                    TVLog.WriteLine("对端类型:" + _screenType.ToString());
                }
                catch (Exception ex)
                {
                    TVLog.WriteLine("ERROR:" + ex.Message);
                }

                RemoteScreenTypeEvent.Invoke(_screenType);
            }
        }

        #endregion


        #region 多人会议

        public static bool isMutilCalling = false;

        private static bool isMutilCallErr = false;

        private static bool isResponse = false;

        public static ConfCallResponse curCCR;

        private static bool isConfCallAddSuccess = false;

        public static VideoConfCallResultHandler VideoConfCallResult;

        public static VideoConfCallResultHandler VideoConfCallAddResult;

        public static VideoConfCallResultHandler VideoConfCallCtrlHaltResult;

        public static VideoConfCallResultHandler VideoConfCallCtlDelResult;

        public static VideoConfCallResultHandler VideoConfCallViewResult;

        public async static void VideoConfCall(string[] members, string called, string callmode, string screenmode, string picnum, string title, string rtmppush)
        {
            if (isMutilCalling) return;

            TVLog.WriteLine("Conference Call start ...");

            string tmpString = "";

            for (int i = 0; i < members.Length; i++)
            {
                tmpString += (i == 0 ? "" : "^") + members[i];
            }

            TVLog.WriteLine("Member list : " + tmpString);

            isMutilCalling = true;

            bool isConfCallSuccess = false;

            Configuration._VideoConfMembers = null;

            WebVideoConfCall wvcc = new WebVideoConfCall(Configuration.CompanyID, Configuration.Account, tmpString, callmode, screenmode, picnum, title, rtmppush);

            wvcc.Call(VideoConfCallResponse);

            int _timeout = 0;

            while (!isResponse | ConferencStatus != ConferencStatusType.Conferencing)
            {
                await Task.Delay(100);

                _timeout += 100;

                if (_timeout > 10000)
                    break;
            }

            if (curCCR != null)
            {
                if (curCCR.status == "200")
                {
                    isConfCallSuccess = true;

                    Configuration.UpdateVideoConfMembers();
                }
            }

            //while (ConferencStatus != ConferencStatusType.Conferencing)
            //{
            //    await Task.Delay(100);
            //}

            //if (isConfCallSuccess)
            //{
            //    //int _i = 0;

            //    //while (_i < members.Length)
            //    //{
            //    VideoConfCtlAdd(tmpString);

            //    //    _i++;

            //    //    await Task.Delay(100);
            //    //}
            //}
            //else
            //{
            //    VideoConfCallResult?.Invoke(null);
            //}
        }

        private static bool isVideoConfCallCancled = true;

        private static bool isVideoConfCallCanclling = false;

        public async static void VideoConfCtrlHalt()
        {
            if (curCCR != null)
            {
                isVideoConfCallCanclling = true;

                isVideoConfCallCancled = false;

                WebVideoConfCtrlHalt wvcch = new WebVideoConfCtrlHalt(Configuration.CompanyID, curCCR.confid);

                wvcch.Call(VideoConfCallCtrlHaltResponse);

                int _timeout = 0;

                while (!isVideoConfCallCancled)
                {
                    await Task.Delay(100);

                    _timeout += 100;

                    if (_timeout > 2000)
                        break;
                }

                Console.WriteLine("结束会议");
            }

            isVideoConfCallCanclling = false;

            isMutilCalling = false;

            Configuration.UpdateVideoConfMembersCancel();

            curCCR = null;
        }

        private static void VideoConfCallCtrlHaltResponse(string response)
        {
            try
            {
                ConfCallResponse _ccr = JsonMapper.ToObject<ConfCallResponse>(response);
                VideoConfCallCtrlHaltResult.Invoke(_ccr);
            }
            catch (Exception ex)
            {
                string log = "Video Conf Call Halt err :" + ex.Message;

                Console.WriteLine(log);

                TVLog.WriteLine(log);

                VideoConfCallCtrlHaltResult = null;

                VideoConfCallCtrlHaltResult.Invoke(null);
            }
            finally
            {
                isVideoConfCallCancled = true;
            }
        }

        private static void VideoConfCallResponse(string response)
        {
            try
            {
                ConfCallResponse _ccr = JsonMapper.ToObject<ConfCallResponse>(response);

                if (_ccr.callflowid != null)
                {
                    curCCR = _ccr;
                }

                VideoConfCallResult?.Invoke(_ccr);

                isResponse = true;
            }
            catch (Exception ex)
            {
                isMutilCallErr = true;

                curCCR = null;

                Console.WriteLine("error : " + ex.Message);

                VideoConfCallResult?.Invoke(null);
            }
        }

        public static void VideoConfCtlAdd(string member)
        {
            if (curCCR?.confid != null)
            {
                WebVideoConfCtrlAdd wvccAdd = new WebVideoConfCtrlAdd(Configuration.CompanyID, member, curCCR.confid);

                wvccAdd.Call(VideoConfCallAddResponse);
            }
        }

        private static void VideoConfCallAddResponse(string response)
        {
            try
            {
                ConfCallResponse _ccr = JsonMapper.ToObject<ConfCallResponse>(response);
                VideoConfCallAddResult.Invoke(_ccr);
            }
            catch (Exception ex)
            {
                string log = "Video Conf Call Add err :" + ex.Message;

                Console.WriteLine(log);

                TVLog.WriteLine(log);

                VideoConfCallAddResult = null;

                VideoConfCallAddResult.Invoke(null);
            }
        }

        public static void VideoConfCtlDel(string member)
        {
            if (curCCR?.confid != null)
            {
                WebVideoConfCtrlDel wvccDel = new WebVideoConfCtrlDel(Configuration.CompanyID, member, curCCR.confid);

                wvccDel.Call(VideoConfCallCtlDel);
            }
        }

        private static void VideoConfCallCtlDel(string response)
        {
            try
            {
                ConfCallResponse _ccr = JsonMapper.ToObject<ConfCallResponse>(response);
                VideoConfCallCtlDelResult.Invoke(_ccr);
            }
            catch (Exception ex)
            {
                string log = "Video Conf Call Del err :" + ex.Message;

                Console.WriteLine(log);

                TVLog.WriteLine(log);

                VideoConfCallCtlDelResult = null;

                VideoConfCallCtlDelResult.Invoke(null);
            }
        }

        public static void VideoConfCtlView(string member)
        {
            if (curCCR?.confid != null)
            {
                WebVideoConfCtrlView wvccView = new WebVideoConfCtrlView(Configuration.CompanyID, member, curCCR.confid);

                wvccView.Call(VideoConfCtlViewResponse);
            }
        }

        private static void VideoConfCtlViewResponse(string response)
        {
            try
            {
                ConfCallResponse _ccr = JsonMapper.ToObject<ConfCallResponse>(response);
                VideoConfCallViewResult.Invoke(_ccr);
            }
            catch (Exception ex)
            {
                string log = "Video Conf Call View err :" + ex.Message;

                Console.WriteLine(log);

                TVLog.WriteLine(log);

                VideoConfCallViewResult = null;

                VideoConfCallViewResult.Invoke(null);
            }
        }

        public static void SetConfCallResponse(ConfCallResponse ccr)
        {
            curCCR = ccr;
        }

        public static void SendConfMessage(string msg)
        {
            if (!string.IsNullOrEmpty(curCCR?.confid))
            {
                if (isMutilCalling)
                {
                    WebVideoConfMsg wvcm = new WebVideoConfMsg(Configuration.CompanyID, curCCR.confid, msg);
                    wvcm.Call(SendConfMessageResult);
                }
            }
        }

        private static void SendConfMessageResult(string response)
        {
            Console.WriteLine("SendConfMessage : " + response);
        }

        #endregion


        public static void Dispose()
        {
            if (ConferencStatus == ConferencStatusType.Conferencing || ConferencStatus == ConferencStatusType.Calling)
            {
                VideoCallCancel();
            }

            //CallResultEvent = null;
            //CallCancelResultEvent = null;
            //VideoCallMeEvent = null;

            //UnRegistCallEvent();
            //UnRegistEvent();
        }

        public static void SetVideoConfCallResult(VideoConfCallResultHandler callback)
        {
            VideoConfCallResult = callback;
        }

        public static void SetVideoConfCallCtlHaltResult(VideoConfCallResultHandler callback)
        {
            VideoConfCallCtrlHaltResult = callback;
        }

        public static void SetVideoConfCallAddResult(VideoConfCallResultHandler callback)
        {
            VideoConfCallAddResult = callback;
        }

        public static void SetVideoConfCallDelResult(VideoConfCallResultHandler callback)
        {
            VideoConfCallCtlDelResult = callback;
        }

        public static void SetVideoConfCallViewResult(VideoConfCallResultHandler callback)
        {
            VideoConfCallViewResult = callback;
        }
    }
}
